/****************************************************************************
 *  A basic key filter. 
 * 	
 *  Here the key is active-low. When key is pressed, output high.
*****************************************************************************/

module keyFilter #(
  parameter   SYS_CLK = 50_000_000
)(
  input       clk ,
  input       rstn,
  input       ikey,

  output reg  okey
);

// localparam CNT_MAX = SYS_CLK / 50;

/*          debug            */
localparam CNT_MAX = 50;

reg  [25:0]     cnt        ;

/*          edge detect         */
reg  key_in_r;
wire key_pos, key_neg;

always @(posedge clk or negedge rstn) begin
  if (~rstn) begin
    key_in_r    <=  1'b1;
  end else begin
    key_in_r    <=  ikey;
  end
end

assign key_pos = (ikey & ~key_in_r) ? 1'b1 : 1'b0;
assign key_neg = (~ikey & key_in_r) ? 1'b1 : 1'b0;

/*          FSM         */
reg  [3:0]  nstate, cstate;
localparam  IDLE   = 4'b0001,
            SAMPLE = 4'b0010,
            PRESS  = 4'b0100,
			      LOOSE	 = 4'b1000;

always @(posedge clk or negedge rstn) begin
  if (~rstn)
    cstate  <=  IDLE;
  else 
    cstate  <=  nstate;
end

always @(*) begin
  nstate = cstate;
  case (cstate)
    IDLE :
      if (key_neg)
				nstate = SAMPLE;
    SAMPLE: 
      begin
        if (okey == 1'b0 && key_pos) begin
          nstate = IDLE;
        end else if (okey == 1'b1 && key_neg) begin
          nstate = PRESS;
        end else if (cnt == CNT_MAX - 1 && okey == 1'b0) begin
			  	nstate = PRESS;
			  end else if (cnt == CNT_MAX - 1 && okey == 1'b1)
			  	nstate = IDLE;
      end
    PRESS:
      if (key_pos)
				nstate = SAMPLE;
    default: nstate = cstate;
  endcase
end

always @(posedge clk or negedge rstn) begin
  if(~rstn)
    okey  <=  1'b0;
  else begin
    case (nstate)
      IDLE : 
    	  okey   <= 1'b0;
      SAMPLE: 
	  		okey   <= okey;
      PRESS: 
     	  okey   <= 1'b1;
      default:
	  		okey   <= okey;
    endcase
  end
end

/*          20ms counter         */
always @(posedge clk or negedge rstn) begin
  if (~rstn) 
    cnt     <=  26'd0;
  else if (nstate == SAMPLE) 
    cnt     <=  cnt + 1'b1;
  else
    cnt     <=  26'd0;
end

endmodule
